from typing import Any

from scrapy import Request
from scrapy.http import Response
from scrapy.pipelines.images import ImagesPipeline
import scrapy
from scrapy.exceptions import DropItem
from scrapy.pipelines.media import MediaPipeline
from scrapy.utils.project import get_project_settings
import os
import hashlib
from urllib.parse import urlparse
from urllib.parse import unquote

class ReptilePicturePipeline(ImagesPipeline):
    # 使用settings.py中的设置
    IMAGES_STORE = get_project_settings().get('IMAGES_STORE')

    def file_path(self, request: Request, response: Response | None = None,
                  info: MediaPipeline.SpiderInfo | None = None, *, item: Any = None) -> str:
        # 获取图片的 URL
        url = unquote(request.url.encode())
        temp = url.split('?', 1)
        url = url.split('?', 1)[0]

        image_guid = hashlib.sha1(url.encode()).hexdigest()
        # 获取图片的扩展名
        image_exts = os.path.splitext(urlparse(url).path)
        if len(image_exts) > 1 and image_exts[1] != '':
            image_ext = image_exts[1]
            image_ext = image_ext.lower().split('@', 1)[0]

        else:
            image_ext = '.jpg'

        print('-------------')
        print(f'{image_guid}{image_ext}')
        # 这里可以根据需求自定义文件名，例如使用图片的哈希值
        return f'{image_guid}{image_ext}'

    # 此函数的第一个对象request就是当前下载对应的scrapy.Request对象，这个方法永汉返回保存的文件名，将图片链接的最后一部分党文文件名，确保不会重复
    # def file_path(self, request, response=None, info=None):
    #
    #     url = request.url
    #     file_name = str(uuid.uuid4())
    #     # 判断图片格式
    #     if url.find("f=PNG") >= 0:
    #         file_name = file_name + ".png"
    #     else:
    #         file_name = file_name + ".jpg"
    #     return file_name

    # 第一个item对象是爬取生成的Item对象，可以将他的url字段取出来，直接生成scrapy.Request对象,此Request加入到调度队列，等待被调度，然后执行下载
    def get_media_requests(self, item, info):
        image_url = item["imageLink"]
        # print("下载---------------")
        # print(image_url)
        # print("下载---------------")
        yield scrapy.Request(image_url)

    # 这是单个Item完成下载时的处理方法，各种原因，并不是每张图片都会下载成功，此方法可以剔除下载失败的图片
    # result是该Item对应的下载结果，是一个列表形式，列表每个元素是一个元组，其中包含了下载成功与失败的信息，这里遍历下载结果，找出所有下载成功的列表，如果列表为空，那么此Item对应的图片链接下载失败，随即跑出异常DropItem，该Item忽略，否则返回Item，该Item有效
    def item_completed(self, results, item, info):
        image_paths = []
        for ok, result in results:
            if ok:
                image_paths.append(result['path'])
            else:
                # 打印下载失败的原因
                print(f"Image download failed: {result}")
        if not image_paths:
            raise DropItem("Item contains no images")
        item['image_paths'] = image_paths
        return item

